package com.ffcs.cn.action.base.table;

import com.ffcs.cn.DevelopProperties;
import com.supermap.desktop.controls.ui.controls.SmDialog;
import com.supermap.desktop.controls.utilities.ComponentFactory;
import com.supermap.desktop.core.ui.controls.GridBagConstraintsHelper;
import com.supermap.desktop.core.ui.controls.SMSpinner;
import com.supermap.desktop.core.utilties.DefaultValues;
import com.supermap.desktop.core.utilties.TableUtilities;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

/**
 * JTable 表格示例代码
 */
public class DialogJTable extends SmDialog {
    private JTable tableNotFixed;
    private CustomTableModel customTableModelNotFixed;
    private JTable tableFixed;
    private CustomTableModel customTableModelFixed;
    private JToolBar toolBar;
    private JButton buttonSelectAll;
    private JButton buttonSelectInvert;
    private JButton buttonDelete;
    private JButton buttonAdd;
    private JLabel labelFixedColumns;
    private SMSpinner spinnerFixedColumns;
    private JScrollPane scrollPane;

    public DialogJTable() {
        //设置标题
        setTitle("JTable 表格");
        //设置初始化窗体大小
        setSize(new Dimension(600, 400));
        //初始化使用的控件
        initComponents();
        //初始化布局，并添加控件
        initLayout();
        //初始化控件监听事件
        initListener();
    }

    private void initComponents() {
        //创建全选按钮
        buttonSelectAll = ComponentFactory.createToolBarButtonSelectAll();
        //创建反选按钮
        buttonSelectInvert = ComponentFactory.createToolBarButtonSelectInverse();
        //创建添加按钮
        buttonAdd = ComponentFactory.createToolBarButtonAddData();
        //创建删除按钮
        buttonDelete = ComponentFactory.createToolBarButtonDelete();
        buttonDelete.setEnabled(false);//默认不可点击
        // 创建固定列文本输入按钮，来输入固定多少列
        this.labelFixedColumns = new JLabel(DevelopProperties.getString("String_Label_FixedColumn"));
        this.spinnerFixedColumns = new SMSpinner(new SpinnerNumberModel(0, 0, 10, 1));
        //创建工具条
        toolBar = new JToolBar();
        //添加按钮到工具条中
        toolBar.add(buttonAdd);
        toolBar.add(buttonDelete);
        //添加分割线
        toolBar.addSeparator();
        toolBar.add(buttonSelectAll);
        toolBar.add(buttonSelectInvert);
        toolBar.addSeparator();
        this.toolBar.add(this.labelFixedColumns);
        this.toolBar.add(this.spinnerFixedColumns);
        //设置工具条禁止拖拽
        toolBar.setFloatable(false);


        //创建不固定列的表格
        this.customTableModelNotFixed = new CustomTableModel(false);
        this.tableNotFixed = new JTable(customTableModelNotFixed);
        // 创建固定列的表格
        this.customTableModelFixed = new CustomTableModel(true);
        this.tableFixed = new JTable(this.customTableModelFixed);
        // 固定表格跟非固定表格共用数据
        this.customTableModelFixed.students = this.customTableModelNotFixed.students;
        this.customTableModelFixed.fixedColumns = this.customTableModelNotFixed.fixedColumns;

        // 固定表格不可用
        this.tableFixed.setEnabled(false);
        // 表格固定大小
        this.tableNotFixed.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        this.tableFixed.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

        this.scrollPane = new JScrollPane(this.tableNotFixed);
        this.scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    }

    private void initLayout() {
        //设置布局为 GridBagLayout 布局
        this.setLayout(new GridBagLayout());

        //添加工具条
        this.add(toolBar, new GridBagConstraintsHelper(0, 0, 1, 1)
                .setInsets(GridBagConstraintsHelper.FRAME_CONTROL_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP, 0, GridBagConstraintsHelper.FRAME_CONTROL_GAP)
                .setWeight(1, 0)
                .setFill(GridBagConstraints.HORIZONTAL));
        //添加表格
        this.add(scrollPane, new GridBagConstraintsHelper(0, 1, 1, 1)
                .setInsets(GridBagConstraintsHelper.CONTROLS_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP)
                .setWeight(1, 1)
                .setFill(GridBagConstraints.BOTH));
    }

    private void initListener() {
        //创建按钮点击监听事件
        ActionListener actionListener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Object source = e.getSource();
                if (source == buttonAdd) {
                    //添加
                    int rowCount = customTableModelNotFixed.getRowCount();
                    customTableModelNotFixed.add(rowCount, createStudent());
                    customTableModelFixed.fireTableDataChanged();
                    //设置选中的行
                    TableUtilities.setTableSelectedRows(tableNotFixed, rowCount);
                    //将滚动条定位到 rowCount 位置
                    TableUtilities.scrollToVisible(tableNotFixed, rowCount, rowCount);
                } else if (source == buttonDelete) {
                    //删除
                    int[] selectedRows = tableNotFixed.getSelectedRows();
                    int[] removeRows = customTableModelNotFixed.remove(selectedRows);
                    TableUtilities.setSelectedRowByDeleted(tableNotFixed, removeRows);
                    customTableModelFixed.fireTableDataChanged();
                } else if (source == buttonSelectAll) {
                    //全选
                    TableUtilities.selectionAll(tableNotFixed);
                    TableUtilities.selectionAll(tableFixed);
                } else if (source == buttonSelectInvert) {
                    //反选
                    TableUtilities.invertSelection(tableNotFixed);
                    TableUtilities.invertSelection(tableFixed);
                }
            }
        };

        //添加监听事件
        buttonAdd.addActionListener(actionListener);
        buttonDelete.addActionListener(actionListener);
        buttonSelectAll.addActionListener(actionListener);
        buttonSelectInvert.addActionListener(actionListener);
        this.spinnerFixedColumns.addChangeListener(this.changeListenerFixedColumns);
        tableNotFixed.getSelectionModel().addListSelectionListener(e -> {
            int[] selectedRows = tableNotFixed.getSelectedRows();
            buttonDelete.setEnabled(selectedRows != null && selectedRows.length > 0);
        });
    }

    // 响应固定列spinner值改变
    private ChangeListener changeListenerFixedColumns = new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent e) {
            int fixedColumnsCount = Integer.parseInt(spinnerFixedColumns.getValue().toString());
            if (fixedColumnsCount != customTableModelNotFixed.fixedColumns.size()) {
                customTableModelNotFixed.fixedColumns.clear();
                if (fixedColumnsCount > 0) {
                    for (int i = 0; i < fixedColumnsCount; i++) {
                        customTableModelNotFixed.fixedColumns.add(customTableModelNotFixed.columns[i]);
                    }
                }
                int systemFontZoomValue = DefaultValues.getSystemFontZoomValue(100);
                if (!customTableModelNotFixed.fixedColumns.isEmpty()) {
                    if (scrollPane.getRowHeader() == null) {
                        scrollPane.setRowHeaderView(tableFixed);// 将固定表格设置给scrollPane RowHeaderView
                        scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, tableFixed.getTableHeader());// 将固定表格猎头填充到scrollPane 左上角，要不然不显示固定表格猎头
                    }
                    Dimension dimension = new Dimension(systemFontZoomValue * customTableModelFixed.fixedColumns.size(), scrollPane.getRowHeader().getPreferredSize().height);
                    scrollPane.getRowHeader().setPreferredSize(dimension);// 设置固定表格所在RowHeaderView 大小，要不然固定表格与非固定表格中间有间隙
                } else {
                    scrollPane.setRowHeader(null);
                }
                customTableModelNotFixed.fireTableStructureChanged();//  表格列发生改动，发出结构改变事件，让UI响应
                customTableModelFixed.fireTableStructureChanged();//  表格列发生改动，发出结构改变事件，让UI响应
                // 表格列发生了变动，重新设置每个列的大小
                for (int i = 0; i < tableFixed.getColumnModel().getColumnCount(); i++) {
                    tableFixed.getColumnModel().getColumn(i).setMinWidth(systemFontZoomValue);
                    tableFixed.getColumnModel().getColumn(i).setPreferredWidth(systemFontZoomValue);
                    tableFixed.getColumnModel().getColumn(i).setMaxWidth(systemFontZoomValue);
                }
                for (int i = 0; i < tableNotFixed.getColumnModel().getColumnCount(); i++) {
                    tableNotFixed.getColumnModel().getColumn(i).setMinWidth(systemFontZoomValue);
                    tableNotFixed.getColumnModel().getColumn(i).setPreferredWidth(systemFontZoomValue);
                    tableNotFixed.getColumnModel().getColumn(i).setMaxWidth(systemFontZoomValue);
                }
            }
        }
    };


    //随机产生一个 Student
    private Student createStudent() {
        SecureRandom random = new SecureRandom();
        Student student = new Student();
        student.setName("student" + random.nextInt(101));
        int[] scores = new int[9];
        for (int i = 0; i < scores.length; i++) {
            // 产生成绩
            scores[i] = random.nextInt(101);
        }
        student.setScores(scores);
        return student;
    }

    //自定义 TableModel
    private class CustomTableModel extends AbstractTableModel {
        //表格列名
        private String[] columns = {"姓名", "语文", "数学", "英语", "历史", "地理", "政治", "物理", "生物", "化学"};
        private List<Student> students = new ArrayList<>();
        private List<String> fixedColumns = new ArrayList<>();// 存储固定列的列名称
        private final static int NAME = 0;
        private boolean fixedModel = false;// 标记当前model是不是固定表格的model


        CustomTableModel(boolean fixedModel) {
            this.fixedModel = fixedModel;
            // 固定表格的数据跟非固定表格数据共享，所以非固定表格需要初始化数据
            if (!fixedModel) {
                for (int i = 0; i < 10; i++) {
                    students.add(DialogJTable.this.createStudent());
                }
            }
        }

        /**
         * 单元格是否可以编辑
         *
         * @param rowIndex    行
         * @param columnIndex 列
         * @return 可否编辑
         */
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            // 固定表格不可编辑，可以自定义
            return !this.fixedModel;
        }

        /**
         * 获取表格行数
         *
         * @return 表格行数
         */
        @Override
        public int getRowCount() {
            return students.size();
        }

        /**
         * 获取表格列数
         *
         * @return 表格列数
         */
        @Override
        public int getColumnCount() {
            // 如果是非固定列，列的个数，要返回总列数-固定列的个数
            if (!this.fixedModel) {
                return columns.length - this.fixedColumns.size();
            } else {
                // 如果是固定列，列的个数，要返回固定列的个数
                return this.fixedColumns.size();
            }
        }

        /**
         * 获取 column 列的列名
         *
         * @param column 列
         * @return 列名
         */
        @Override
        public String getColumnName(int column) {
            return this.columns[getColumnIndex(column)];
        }

        /**
         * 因为getColumnCount()返回的是固定列的个数或排除固定列的个数，比如总列数10，固定了4列，那么固定表格调用的列索引就是0 1 2 3，非固定表格就是0 1 2 3 4 5，所以需要将列索引，根据是不是固定别，还原到真实列索引0——9
         *
         * @param column 列索引
         * @return 跟this.columns匹配的索引
         */
        private int getColumnIndex(int column) {
            if (!this.fixedModel) {
                int newColumn = -1;
                for (int i = 0; i < this.columns.length; i++) {
                    if (this.fixedColumns.contains(this.columns[i])) {
                        continue;
                    }
                    newColumn += 1;
                    if (newColumn == column) {
                        return i;
                    }
                }
            } else {
                int newColumn = -1;
                for (int i = 0; i < this.columns.length; i++) {
                    if (!this.fixedColumns.contains(this.columns[i])) {
                        continue;
                    }
                    newColumn += 1;
                    if (newColumn == column) {
                        return i;
                    }
                }
            }
            return -1;
        }

        /**
         * 获取 rowIndex 行和 column 列的数据对象
         *
         * @param rowIndex 行
         * @param column   列
         * @return 数据对象
         */
        @Override
        public Object getValueAt(int rowIndex, int column) {
            Student student = students.get(rowIndex);
            int columnIndex = getColumnIndex(column);
            if (columnIndex == NAME) {
                return student.getName();
            } else {
                return student.getScores()[columnIndex - 1];
            }
        }

        /**
         * 设置表格值
         *
         * @param aValue   新值
         * @param rowIndex 行
         * @param column   列
         */
        @Override
        public void setValueAt(Object aValue, int rowIndex, int column) {
            int columnIndex = getColumnIndex(column);
            if (column == NAME) {
                setName(aValue, rowIndex);
            } else {
                try {
                    this.students.get(rowIndex).getScores()[columnIndex - 1] = Integer.parseInt(aValue.toString());
                } catch (Exception e) {
                    //设置失败则保持原来的值
                }
            }
        }


        private void setName(Object name, int rowIndex) {
            String newName = name == null ? "" : name.toString();
            students.get(rowIndex).setName(newName);
        }

        /**
         * 添加数据到表格
         *
         * @param row     行
         * @param student 数据
         */
        void add(int row, Student student) {
            students.add(row, student);
            fireTableDataChanged();
        }

        /**
         * 移除表格数据
         *
         * @param rows 移除数据所在的行数
         * @return 成功移除的行数
         */
        int[] remove(int... rows) {
            ArrayList<Integer> list = new ArrayList<>();
            for (int i = rows.length - 1; i >= 0; i--) {
                int value = rows[i];
                if (students.remove(value) != null) {
                    list.add(value);
                }
            }
            if (!list.isEmpty()) {
                fireTableDataChanged();
                int[] result = new int[list.size()];
                for (int i = 0; i < list.size(); i++) {
                    result[i] = list.get(i);
                }
                return result;
            }

            return new int[0];
        }
    }

    //创建一个学生的实体类
    private static class Student {
        private String name;

        private int scores[] = new int[9];

        Student() {
        }

        Student(String name) {
            this.name = name;
        }

        String getName() {
            return name;
        }


        void setName(String name) {
            this.name = name;
        }

        public int[] getScores() {
            return scores;
        }

        public void setScores(int[] scores) {
            this.scores = scores;
        }
    }
}
